From cc3ec9c20c61904b8ebb41593d6814a0f54b6dc4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Sat, 20 Sep 2025 18:19:06 +0200 Subject: [PATCH] odhcpd: support IAIDs for static DHCPv6 leases MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Extend the string format for duids to alternatively support "%", which makes it possible to define separate static leases, e.g. for a client which is connected to the same network with more than one interface (which will both have the same DUID, as it is a per-host identifier, but different IAIDs). Note that this only wires up the new format, actually using it to make DHCPv6-IA decisions will be implemented in subsequent patches. Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/255 Signed-off-by: Álvaro Fernández Rojas --- README.md | 2 +- src/config.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- src/odhcpd.h | 4 ++++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b710b93..69d7a6c 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ and may also receive information from ubus | :-------------------- | :---- | :---- | :---------- | | ip |string |(none) | IPv4 host address | | mac |list\|string|(none) | HexadecimalMACaddress(es) | -| duid |string |(none) | HexadecimalDUID | +| duid |string |(none) | Hexadecimal DUID, or DUID%IAID | | hostid |string |(none) | IPv6hostidentifier | | name |string |(none) | Hostname | | leasetime |string |(none) | DHCPv4/v6leasetime | diff --git a/src/config.c b/src/config.c index 0dcef1b..5f072ea 100644 --- a/src/config.c +++ b/src/config.c @@ -469,7 +469,7 @@ int set_lease_from_blobmsg(struct blob_attr *ba) struct lease *l = NULL; int mac_count = 0; struct ether_addr *macs; - size_t duidlen = 0; + size_t duid_alloc_size = 0; uint8_t *duid; blobmsg_parse(lease_attrs, LEASE_ATTR_MAX, tb, blob_data(ba), blob_len(ba)); @@ -481,11 +481,12 @@ int set_lease_from_blobmsg(struct blob_attr *ba) } if ((c = tb[LEASE_ATTR_DUID])) - duidlen = (blobmsg_data_len(c) - 1) / 2; + /* We might overallocate some bytes here, that's fine */ + duid_alloc_size = (blobmsg_data_len(c) - 1) / 2; l = calloc_a(sizeof(*l), &macs, mac_count * sizeof(*macs), - &duid, duidlen); + &duid, duid_alloc_size); if (!l) goto err; @@ -503,15 +504,50 @@ int set_lease_from_blobmsg(struct blob_attr *ba) } if ((c = tb[LEASE_ATTR_DUID])) { - ssize_t len; + const char *duid_str = blobmsg_get_string(c); + size_t duid_str_len = blobmsg_data_len(c) - 1; + ssize_t duid_len; + const char *iaid_str; + + /* We support a hex string with either "", or "%" */ + iaid_str = strrchr(duid_str, '%'); + if (iaid_str) { + size_t iaid_str_len = strlen(++iaid_str); + + /* IAID = uint32, RFC8415, §21.4, §21.5, §21.21 */ + if (iaid_str_len < 1 || iaid_str_len > 2 * sizeof(uint32_t)) { + syslog(LOG_ERR, "Invalid IAID length '%s'", iaid_str); + goto err; + } - l->duid = duid; - len = odhcpd_unhexlify(l->duid, duidlen, blobmsg_get_string(c)); + errno = 0; + l->iaid = strtoull(iaid_str, NULL, 16); + if (errno) { + syslog(LOG_ERR, "Invalid IAID '%s'", iaid_str); + goto err; + } + + l->iaid_set = true; + duid_str_len -= (iaid_str_len + 1); + } + + if (duid_str_len < 2 || duid_str_len > DUID_MAX_LEN * 2 || duid_str_len % 2) { + syslog(LOG_ERR, "Invalid DUID length '%.*s'", (int)duid_str_len, duid_str); + goto err; + } - if (len < 0) + l->duid = duid; + duid_len = odhcpd_unhexlify(l->duid, duid_str_len / 2, duid_str); + if (duid_len < 0) { + syslog(LOG_ERR, "Invalid DUID '%.*s'", (int)duid_str_len, duid_str); goto err; + } - l->duid_len = len; + l->duid_len = duid_len; + syslog(LOG_DEBUG, + "Found a static lease for DUID '%.*s' (%zi bytes), IAID 0x%08" PRIx32 "%s", + (int)duid_str_len, duid_str, duid_len, + l->iaid, l->iaid_set ? "" : " (not defined)"); } if ((c = tb[LEASE_ATTR_NAME])) { diff --git a/src/odhcpd.h b/src/odhcpd.h index 0903487..e225108 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -180,6 +180,8 @@ struct config { int log_level; }; +/* 2-byte type + 128-byte DUID, RFC8415, §11.1 */ +#define DUID_MAX_LEN 130 struct lease { struct vlist_node node; @@ -190,6 +192,8 @@ struct lease { struct ether_addr *macs; uint16_t duid_len; uint8_t *duid; + uint32_t iaid; + bool iaid_set; uint32_t leasetime; char *hostname; }; -- 2.30.2